﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TinyROS.Messages;
using TinyROS.Exceptions;

namespace TinyROS
{
    partial class SystemCore
    {
        // 这一部分负责处理命令行的解析和调度
        // TODO:尝试使用正则表达式匹配命令？
        private const StringSplitOptions SplitOption = StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries;
        public void ConsoleSpin()
        {
            this.Exit = false;

            while (!this.Exit)
            {
                try
                {
                    ConsoleWriteWithColor("TinyROS > ", ConsoleColor.Blue);
                    var cmd = Console.ReadLine();
                    if (cmd != "")
                    {
                        this.Execute(cmd);
                    }
                }
                catch
                {

                }
            }
        }
        private enum CommandBaseType { Node, Topic, Core }
        private enum NodeCommandType { New, Delete, Start, Stop, Info, List, Execute }
        private enum TopicCommandType { New, Delete, Publish, Echo, Show, List }
        private enum CoreCommandType { Exit, Restart, Config, AsmLoad, Script, Help }
        public void Execute(string command)
        {
            try
            {
                command = command.Trim();
                (var baseType, var subBaseCmd) = this.ParseBaseCommand(command);
                switch (baseType)
                {
                    case CommandBaseType.Node:
                        (var nodeCmdType, var subNodeCmd) = this.ParseNodeCommand(subBaseCmd);
                        switch (nodeCmdType)
                        {
                            case NodeCommandType.New:
                                this.NodeNewHandler(subNodeCmd);
                                break;
                            case NodeCommandType.Delete:
                                this.NodeDeleteHandler(subNodeCmd);
                                break;
                            case NodeCommandType.Start:
                                this.NodeStartHandler(subNodeCmd);
                                break;
                            case NodeCommandType.Stop:
                                this.NodeStopHandler(subNodeCmd);
                                break;
                            case NodeCommandType.Info:
                                this.NodeInfoHandler(subNodeCmd);
                                break;
                            case NodeCommandType.List:
                                this.NodeListHandler();
                                break;
                            case NodeCommandType.Execute:
                                this.NodeExecuteHandler(subNodeCmd);
                                break;
                        }
                        break;
                    case CommandBaseType.Topic:
                        (var topicCmdType, var subTopicCmd) = this.ParseTopicCommand(subBaseCmd);
                        switch (topicCmdType)
                        {
                            case TopicCommandType.New:
                                this.TopicNewHandler(subTopicCmd); 
                                break;
                            case TopicCommandType.Delete:
                                break;
                            case TopicCommandType.Echo:
                                this.TopicEchoHandler(subTopicCmd);
                                break;
                            case TopicCommandType.Publish:
                                this.TopicPublishHandler(subTopicCmd);
                                break;
                            case TopicCommandType.Show:
                                break;
                            case TopicCommandType.List:
                                this.TopicListHandler();
                                break;
                        }
                        break;
                    case CommandBaseType.Core:
                        (var coreCmdType, var coreCmd) = this.ParseCoreCommand(subBaseCmd);
                        switch (coreCmdType)
                        {
                            case CoreCommandType.Exit:

                                break;
                            case CoreCommandType.Restart:
                                break;
                            case CoreCommandType.AsmLoad:
                                this.LoadAssemblyHandler(coreCmd);
                                break;

                            case CoreCommandType.Config:
                                break;
                            case CoreCommandType.Script:
                                this.ExecuteScriptHandler(coreCmd);
                                break;
                            case CoreCommandType.Help:
                                this.HelpHandler();
                                break;
                        }
                        break;
                }
            }
            catch (ArgumentCountException ce)
            {
                LogError($"命令参数数目不正确({ce.Command})", "Command parse");
            }
            catch (CommandNotFoundException ne)
            {
                LogError($"未找到命令({ne.Command})", "Command parse");
            }
            catch
            {

            }
        }

        private (CommandBaseType baseType, string subCmd) ParseBaseCommand(string cmd)
        {
            try
            {
                var baseCmd = cmd.Split(" ", 2, SplitOption);
                switch (baseCmd[0])
                {
                    case "Node":
                    case "node":
                        return (CommandBaseType.Node, baseCmd[1]);
                    case "Topic":
                    case "topic":
                        return (CommandBaseType.Topic, baseCmd[1]);
                    default:
                        return (CommandBaseType.Core, cmd);
                }
            }
            catch(IndexOutOfRangeException)
            {
                throw new ArgumentCountException(cmd);
            }
            catch
            {
                throw;
            }
        }
        private (NodeCommandType nodeCommandType, string args) ParseNodeCommand(string cmd)
        {
            try
            {
                var nodeCmd = cmd.Split(" ", 2, SplitOption);
                switch (nodeCmd[0])
                {
                    case "new":
                        return (NodeCommandType.New, nodeCmd[1]);
                    case "run":
                        return (NodeCommandType.Start, nodeCmd[1]);
                    case "delete":
                        return (NodeCommandType.Delete, nodeCmd[1]);
                    case "stop":
                        return (NodeCommandType.Stop, nodeCmd[1]);
                    case "info":
                        return (NodeCommandType.Info, nodeCmd[1]);
                    case "list":
                        return (NodeCommandType.List, null);
                    case "execute":
                        return (NodeCommandType.Execute, nodeCmd[1]);
                    default:
                        throw new CommandNotFoundException(nodeCmd[0]);
                }
            }
            catch(IndexOutOfRangeException)
            {
                throw new ArgumentCountException(cmd);
            }
            catch
            {
                throw;
            }
        }
        private (TopicCommandType topicCommandType, string args) ParseTopicCommand(string cmd)
        {
            try
            {
                var topicCmd = cmd.Split(" ", 2, SplitOption);
                switch(topicCmd[0])
                {
                    case "new":
                        return (TopicCommandType.New, topicCmd[1]);
                    case "delete":
                        return (TopicCommandType.Delete, topicCmd[1]);
                    case "pub":
                    case "publish":
                        return (TopicCommandType.Publish, topicCmd[1]);
                    case "list":
                        return (TopicCommandType.List, null);
                    case "show":
                        return (TopicCommandType.Show, topicCmd[1]);
                    case "echo":
                        return (TopicCommandType.Echo, topicCmd[1]);
                    default:
                        throw new CommandNotFoundException(topicCmd[0]);
                }
            }
            catch(IndexOutOfRangeException)
            {
                throw new ArgumentCountException(cmd);
            }
            catch
            {
                throw;
            }
        }
        private (CoreCommandType coreCommandType, string args) ParseCoreCommand(string cmd)
        {
            try
            {
                var coreCmd = cmd.Split(" ", 2, SplitOption);
                switch(coreCmd[0])
                {
                    case "exit":
                    case "Exit":
                        return (CoreCommandType.Exit, null);
                    case "restart":
                    case "Restart":
                        return (CoreCommandType.Restart, null);
                    case "load":
                    case "Load":
                        return (CoreCommandType.AsmLoad, coreCmd[1]);
                    case "config":
                    case "Config":
                        return (CoreCommandType.Config, coreCmd[1]);
                    case "execute":
                    case "Execute":
                        return (CoreCommandType.Script, coreCmd[1]);
                    case "help":
                        return (CoreCommandType.Help, null);
                    default:
                        throw new CommandNotFoundException(coreCmd[0]);
                }
            }
            catch(IndexOutOfRangeException)
            {
                throw new ArgumentCountException();
            }
            catch
            {
                throw;
            }
        }
        public static void LogInfo(string content, string head)
        {
            ConsoleWriteLineWithColor($"[INFO-{head}]:{content}", ConsoleColor.Green);
        }
        public static void LogWaring(string content, string head)
        {
            ConsoleWriteLineWithColor($"[WARN-{head}]:{content}", ConsoleColor.Yellow);
        }
        public static void LogError(string content, string head)
        {
            ConsoleWriteLineWithColor($"[ERROR-{head}]:{content}", ConsoleColor.Red);
        }
        public static void ConsoleWriteWithColor(string s, ConsoleColor color)
        {
            var originColor = Console.ForegroundColor;
            Console.ForegroundColor = color;
            Console.Write(s);
            Console.ForegroundColor = originColor;
        }
        public static void ConsoleWriteLineWithColor(string s, ConsoleColor color)
        {
            var originColor = Console.ForegroundColor;
            Console.ForegroundColor = color;
            Console.WriteLine(s);
            Console.ForegroundColor = originColor;
        }
    }
}
